home *** CD-ROM | disk | FTP | other *** search
- /* pe7mai.c */
- /*
- * K e r m i t File Transfer Utility
- *
- * UNIX Kermit, Columbia University, 1981, 1982, 1983
- * Bill Catchings, Bob Cattani, Chris Maio, Frank da Cruz, Alan Crosswell
- *
- * Also: Jim Guyton, Rand Corporation
- * Walter Underwood, Ford Aerospace
- *
- * usage kermit -s [-f -d -i -u -t -p -l -b] file ... to send files
- * kermit -r [-d -i -u -t -p -l -b] to receive files
- * kermit -g [-f -d -i -u -t -p -l -b] file ... to get files
- * kermit -f [-d -t -p -l] to send finish command
- * kermit -x [-d -v -i -u -t -p -l] to set server mode
- * where s=send <flag>, r=receive <flag>, x=server <flag>,
- * f=finish mode <flag>, g=get files mode <flag>,
- * d=debug level <number>, v=verbose mode <flag>,
- * i= image mode <flag>, u=no file name conversion <flag>
- * l=tty line <device>, b=baud rate <speed>,
- * t=turnaround mode <flag>, p=parity type <char>
- */
-
- /*
- * Modification History:
- *
- * Version 1.1(0)
- * December 4, 1986 - Add btobemp to decode other prefixxed packets.
- * - Split program into parts to allow compiling on
- * machine with minimum memory configuration.
- * put in version number (use -v flag)
- * Chris Lent (ihnp4!philabs!phri!cooper!chris)
- * March 85 - Change to use the IDRIS operating system
-
- * Oct. 17 Included fixes from Alan Crosswell (CUCCA) for IBM_UTS:
- * - Changed MYEOL character from \n to \r.
- * - Change char to int in bufill so getc would return -1 on
- * EOF instead of 255 (-1 truncated to 8 bits)
- * - Added read() in rpack to eat the EOL character
- * - Added fflush() call in printmsg to force the output
- * NOTE: The last three changes are not conditionally compiled
- * since they should work equally well on any system.
- *
- * Changed Berkeley 4.x conditional compilation flag from
- * UNIX4X to UCB4X.
- * Added support for error packets and cleaned up the printing
- * routines.
- */
- #define KVERSION "Perkin-Elmer 7000 Series 1.1(0) 5 Dec 86"
- #define UTEXT 0 /* Set for 8 bit text strings */
-
- #include <std.h> /* Standard UNIX definitions */
- #include <sys.h> /* Idris system subroutines */
- /*#include "sgtty.h" /* Special tty defs */
- #include "pe7tty.h" /* Special tty defs */
-
- /* Symbol Definitions */
-
- #define BUFSIZE 80 /* A buffer size for I/O */
- #define MAXTRY 8 /* Times to retry a packet */
- #define SOH 1 /* Start of header */
- #define CR 13 /* ASCII Carriage Return */
- #define XON 17 /* ASCII xon character */
- #define SP 32 /* ASCII space */
- #define DEL 127 /* Delete (rubout) */
-
- #define MAXPACKSIZ 94 /* Maximum packet size */
- #define DEFPACKSIZ 80 /* The default packet size */
- #define MAXFNAME 50 /* My maximum for filename length */
- #define SPOVER 14 /* The closest I may come to the end of the output
- buffer */
- #define MYTIME 10 /* Seconds after which I should be timed out */
- #define MYPAD 0 /* Number of padding characters I will need */
- #define MYPCHAR 0 /* Padding character I need (NULL) */
- #define MYEOL '\r' /* End-Of-Line character I need */
- #define MYQUOTE '#' /* Quote character I will use */
- #define DEFQBIN 'Y' /* I will do binary quoting */
- #define MYQBIN '&' /* Binary quoting character */
- #define DEFCHKT '1' /* Default Check sum type */
- #define MYCHKT '1' /* Check sum type */
- #define DEFREPT '~' /* Repeat character I will use */
- #define MYREPT '~' /* Repeat character that I need */
- #define TRUE -1 /* Boolean constants */
- #define FALSE 0
-
-
- /* Macro Definitions */
-
- /*
- * tochar: convert a control character to a printable one by adding a space.
- *
- * unchar: undoes tochar.
- *
- * ctl: converts between control characters and printable characters by
- * toggling the control bit (ie. ^A becomes A and A becomes ^A).
- */
-
- #define tochar(ch) ((ch) + ' ')
- #define unchar(ch) ((ch) - ' ')
- #define ctl(ch) ((ch) ^ 64)
-
- /* Global Variables */
-
- /* This is the format for the return packet from the other user */
- int
- spsiz {MAXPACKSIZ}, /* Maximum send packet size */
- timint {MYTIME}, /* Timeout for foreign host on sends */
- pad {0}; /* How much padding to send */
- TEXT
- padchar {0}, /* Padding character to send */
- eol {MYEOL}, /* End-Of-Line character to send */
- quote {MYQUOTE}, /* Quote character in incoming data */
- qbin {0}, /* binary conversion character */
- chkt {MYCHKT}, /* Checksum type '1','2', or '3' */
- rept {0}; /* Repeat character if repeat supported */
-
- int
- size[2] {0}, /* Size of present data in packets */
- empty[2] {0}, /* Packets ok to fill if zero */
- pknum {0}, /* Current packet buffer index */
- n {0}, /* Packet number */
- nxo {0}, /* Output packet counter for display */
- nxi {0}, /* Nak packet counter for display */
- nxs {0}, /* Saved nak counter */
- repeat_count {0}, /* Repeat counter for repeated characters */
- numtry {0}, /* Times this packet retried */
- oldtry {0}, /* Times previous packet retried */
- iflg {0}, /* Indicates to turn on the image mode */
- image {0}, /* -1 means 8-bit mode (driven by iflg) */
- speed {0}, /* baud rate of the link */
- fflg {0}, /* Indicates to send finish command */
- rflg {0}, /* Indicates receive mode */
- sflg {0}, /* Indicates send mode */
- xflg {0}, /* Indicates server mode */
- gflg {0}, /* Indicates get file mode */
- vflg {0}, /* Verbose messages in server mode */
- tflg {0}, /* Turn around flag */
- pflg {0}, /* What kind of parity are we using? */
- spflg {0}, /* This is our start-up parity flag */
- debug {0}, /* indicates level of debugging output (0=none) */
- filnamcnv {0}, /* -1 means do file name case conversions */
- filecount {0}; /* Number of files left to send */
-
- TEXT
- state {0}, /* Present state of the automaton */
- rqbin {0}, /* 8 bit quote character saved in rpar */
- sqbin {0}, /* 8 bit quote character used in spar */
- rrept {0}, /* Repeat character used in spar */
- **filelist {0}, /* List of files to be sent */
- *filnam {0}, /* Current file name */
- *files[10] {0}, /* Pointers for the server file names */
- filename_buffer[MAXPACKSIZ] {0}; /* Buffer for the server file name */
- TEXT
- recpkt[MAXPACKSIZ] {0}, /* Receive packet buffer */
- *packet[2] {0}, /* Packet pointers */
- packet0[MAXPACKSIZ] {0}, /* Send packet zero buffer */
- packet1[MAXPACKSIZ] {0}; /* Send packet one buffer */
-
- FILE ttyfd {0}; /* File descriptor of tty for I/O, 0 if remote */
-
- FIO *fd {0}; /* pfio pointer */
- FIO pfio {0}; /* Buffer structure for the files */
-
- struct tty
- ttymode {0}, /* tty raw mode */
- savemode {0}; /* tty cooked mode */
-
- struct {
- int files; /* Number of files */
- int fc; /* Number of characters in files */
- int pli; /* Number of packets received */
- int plo; /* Number of packets sent */
- int cli; /* Number of characters received */
- int clo; /* Number of characters sent */
- ULONG time; /* Total time for transaction */
- } total {0}, file {0};
-
- /*
- * m a i n
- *
- * Main routine - parse command and options, set up the
- * tty lines, and dispatch to the appropriate routine.
- *
- */
-
- main(argc,argv)
- int argc; /* Character pointers to and count of */
- char **argv; /* command line arguments */
-
- {
- TEXT *ttyname, /* tty name for LINE argument */
- *cp; /* char pointer */
-
- printf("IDRIS Kermit - %s",KVERSION);
- if (argc < 2) /* Make sure there's a command line */
- Usage("Invalid command line - Not enough arguments.");
- packet[0] = &packet0; /* Set up the packet pointers */
- packet[1] = &packet1;
-
- /* Turn off the parse flags */
- sflg = FALSE;
- rflg = FALSE;
- xflg = FALSE;
- gflg = FALSE;
- fflg = FALSE;
- image = iflg = FALSE;
- filnamcnv = TRUE; /* conversion for UNIX systems */
- vflg = FALSE; /* Turn off verbose flags */
- debug = FALSE; /* Turn off the debug mode */
- ttyname = 0; /* We did not get a line assignment (pointer) */
- speed = FALSE; /* Speed not indicated */
- spflg = pflg = FALSE; /* Parity is not indicated */
- tflg = FALSE; /* No turn around character */
-
- sqbin = DEFQBIN; /* Set up default qbin character */
- rqbin = sqbin;
- qbin = FALSE;
-
- /* Reset the display counters */
- nxo = 0;
- nxi = 0;
- nxs = -1;
-
- getflags(&argc,&argv,\
- "s,r,x,g,f,i,u,v,d#,l*,b#,p?,t:F <file>",\
- &sflg, &rflg, &xflg, &gflg, &fflg, &iflg, &filnamcnv, &vflg,\
- &debug, &ttyname, &speed, &pflg, &tflg);
-
- if (!ttyname) /* If LINE was not specified, use default */
- ttyname = "/dev/lnk0";
- ttyfd = open(ttyname, UPDATE, 0);/* Open the tty line */
- if (ttyfd <= 0)
- Usage("Cannot open %s.",ttyname);
-
- /* Put the proper tty into the correct mode */
- egtty(ttyfd,&savemode); /* save for later use */
- egtty(ttyfd,&ttymode); /* set for changing the setup */
-
- printf("IDRIS Kermit - %s",KVERSION);
- vflg = vflg ? vflg : fflg || gflg || rflg || sflg || debug ?
- TRUE : FALSE;
-
- if ((gflg + xflg + rflg + sflg) != 1) /* Only one command allowed */
- if (!fflg)
- Usage("Only one command allowed - g ! r ! s ! x.");
-
- if (fflg && (xflg || rflg))
- Usage("Finish with server or receive?");
-
- if (!pflg) /* Do we set up the parity? */
- {
- /* Check for raw mode and if true then force no parity */
- if (ttymode.t_mode & M_RAW) pflg = FALSE;
- else
- {
- /* What has the caller set into the hardware */
- switch (ttymode.t_mode & (M_EVEN | M_ODD))
- {
- case M_ODD:
- pflg = 'o';
- break;
- case M_EVEN:
- pflg = 'e';
- break;
- case M_EVEN | M_ODD:
- pflg = 'm';
- break;
- case 0:
- pflg = 's';
- }
- }
- }
- else
- {
- if (scnbuf("neoms",5,pflg) == 5)
- Usage("Improper parity call out.");
- if (pflg == 'n') pflg = FALSE; /* If no parity then set it */
- }
- spflg = pflg; /* Set up start-up parity */
-
- /* Put the hardware into raw mode */
- ttymode.t_mode = (M_RAW | M_ALL | MR_XON);
-
- if (speed) /* Do we set up the speed? */
- {
- switch (speed)
- {
- case 110:
- speed = B110;
- ttymode.t_mode |= M_2STOP;
- break;
- case 150:
- speed = B150;
- break;
- case 300:
- speed = B300;
- break;
- case 1200:
- speed = B1200;
- break;
- case 2400:
- speed = B2400;
- break;
- case 4800:
- speed = B4800;
- break;
- case 9600:
- speed = B9600;
- break;
- default:
- Usage("Bad line speed.");
- }
- ttymode.t_ispeed = speed;
- ttymode.t_ospeed = speed;
- }
- /* Set up the time-out and buffer size */
- ttymode.t_min = 128;
- ttymode.t_time = MYTIME * 10;
- if (tflg) /* Turn around flag on? */
- ttymode.t_cgo = NULL; /* Turn off XON in XON/XOFF */
-
- estty(ttyfd,&ttymode); /* Put asg'd tty in requested mode */
-
- /* All set up, now execute the command that was given. */
-
- if (filnamcnv > 0) /* Do we want to do file name conversions? */
- filnamcnv = FALSE;
-
- if (iflg) /* Turn on the image mode? */
- {
- image = TRUE;
- /* Test the parity and make a determination of the qbin
- mode info */
- if (pflg) /* Pflg contains the parity bit if set */
- sqbin = MYQBIN; /* Set 8-bit quoting */
- else
- sqbin = DEFQBIN; /* We can do 8 bit transfers */
- }
-
- if (debug)
- {
- printf("Main 1: S=%d, R=%d, X=%d, G=%d,", sflg, rflg, xflg, gflg);
- printf(" F=%d, I=%d, U=%d, V=%d,", fflg, iflg, filnamcnv, vflg);
- printf(" D=%d\n", debug);
- printf(" L=%s, B=%d, P=%c,", ttyname, speed, pflg);
- printf(" T=%d\n", tflg);
- printf("Main 2: Bits for ttyfd %x\n",ttymode.t_mode);
- }
- if (gflg || sflg)
- {
- /* Anything to get or send? */
- if (argc--)
- filnam = *argv++; /* Get file to send */
- else
- {
- savemode.t_time = 0;
- estty(ttyfd,&savemode); /* restore the old mode */
- Usage("File name required.");
- /* and give error */
- }
- fd = NULL; /* Indicate no file open yet */
- filelist = argv; /* Set up the rest of the file list */
- filecount = argc; /* Number of files left to get or send */
- }
-
- dostat(1);
-
- if (gflg) /* Get command */
- {
- if (debug) printf("Main 3: Get command\n");
- if (getsw() == FALSE)
- Usage("Get failed.");
- else
- printmsg("Get done.");
- }
-
- if (sflg) /* Send command */
- {
- if (debug) printf("Main 4: Send command\n");
- if (sendsw() == FALSE) /* Send the file(s) */
- Usage("Send failed."); /* Report failure */
- else /* or */
- printmsg("Send done."); /* success */
- }
- /* end of sflg */
-
- if (rflg) /* Receive command */
- {
- if (debug) printf("Main 5: Receive command\n");
- if (debug < 3)
- {
- if (recsw() == FALSE) /* Receive the file(s) */
- Usage("Receive failed.");
- else /* Report failure */
- printmsg("Receive done."); /* or success */
- }
- /* End of test for no receive of data (debug < 3) */
- }
- /* End of (rflg) test */
-
- if (xflg)
- while (server() == TRUE);
-
- if (fflg)
- {
- if (debug) printf("Main 6: Finish command\n");
- if (finishsw() == FALSE)
- Usage("Finish failed.");
- else
- printmsg("Finish done.");
- }
-
- if (vflg)
- if(total.files > 1)
- {
- printf("%d Files\n", total.files);
- printf("%d Bytes %d Seconds %d/%d Packets",
- total.fc, total.time, total.plo, total.pli);
- printf(" %d/%d Characters\n", total.clo, total.cli);
- }
-
- /* Restore the tty (reset the timeout to infinite) */
- savemode.t_time = 0;
- estty(ttyfd,&savemode);
- exit(YES);
- }
-
- /*
- * s e n d s w
- *
- * Sendsw is the state table switcher for sending files. It loops until
- * either it finishes, or an error is encountered. The routines called
- * by sendsw are responsible for changing the state.
- *
- */
-
- sendsw()
- {
- TEXT sinit(), sfile(), sdata(), seof(), sbreak();
-
- n = 0; /* Initialize message number */
- numtry = 0; /* Say no tries yet */
- state = 'S'; /* Send initiate is the start state */
- while(TRUE) /* Do this as long as necessary */
- {
- if (debug) printf("Sendsw 1: State: %c\n",state);
- switch(state)
- {
- case 'S': state = sinit(); break; /* Send-Init */
- case 'T': state = sfile(); break; /* Send-File */
- case 'E': state = sdata(); break; /* Send-Data */
- case 'Z': state = seof(); break; /* Send-End-of-File */
- case 'B': state = sbreak(); break; /* Send-Break */
- case 'C': return (TRUE); /* Complete */
- case 'A': /* "Abort" */
- default: return (FALSE); /* Unknown, fail */
- }
- }
- }
-
- /*
- * r e c s w
- *
- * This is the state table switcher for receiving files.
- *
- */
-
- recsw()
- {
- TEXT rinit(), rfile(), rdata(); /* Use these procedures */
-
- n = 0; /* Initialize message number */
- numtry = 0; /* Say no tries yet */
- state = 'R'; /* Receive-Init is the start state */
- while(TRUE)
- {
- if (debug) printf("Recsw 1: state: %c\n",state);
- switch(state) /* Do until done */
- {
- case 'R': state = rinit(); break; /* Receive-Init */
- case 'F': state = rfile(); break; /* Receive-File */
- case 'D': state = rdata(); break; /* Receive-Data */
- case 'C': return (TRUE); /* Complete state */
- case 'A':
- default: return (FALSE); /* "Abort" state */
- }
- }
- }
-
- /*
- * g e t s w
- *
- * Get a file from the other end
- *
- */
-
- getsw()
- {
- TEXT ginit(), iinit(), rfile(), rdata(); /* Use these procedures */
- TEXT filnam1[MAXFNAME],
- *newfilnam,
- *cp;
- int num, len;
-
- cpystr(filnam1, filnam, NULL); /* Copy file name */
- newfilnam = cp = filnam1;
- while (*cp != '\0')
- if (*cp++ == '/')
- newfilnam = cp;
- if (filnamcnv) /* Convert lower case to upper */
- for (cp = newfilnam; *cp != '\0'; cp++)
- *cp = toupper(*cp);
- len = cp - newfilnam;
- printmsg("Requesting %s as %s",filnam, newfilnam);
- n = 0; /* Initialize message number */
- numtry = 0; /* Say no tries yet */
- state = 'S';
- while (TRUE)
- {
- if (debug) printf("Getsw 1: State: %c\n",state);
- switch (state)
- {
- case 'S': state = iinit(); break; /* Try this */
- /* Then this */
- case 'R': state = ginit(len,newfilnam); break;
- case 'F': state = rfile(); break; /* Fetch file name */
- case 'D': state = rdata(); break; /* Fetch the data */
- case 'C': return (TRUE); /* End it all goodly */
- case 'A':
- default: return (FALSE); /* End it all badly */
- }
- }
- }
-
- /*
- * s e r v e r
- *
- * This is the state table switcher for the server mode
- *
- */
-
- server()
- {
- TEXT xinit(), rfile(), rdata(); /* Use these procedures */
- TEXT sinit(), xfile(), sdata(), seof(), sbreak(); /* and these */
-
- image=iflg;
- pflg=spflg;
- n = 0; /* Initialize message number */
- numtry = 0; /* Say no tries yet */
- state = 'X'; /* Begin is the start state */
- while(TRUE)
- {
- if (debug) printf("Server 1: state: %c\n",state);
- switch(state) /* Do until done */
- {
- case 'X': state = xinit(); break; /* Fetch what to do */
- case 'S': state = sinit(); break; /* Send init packets */
- case 'T': state = xfile(); break; /* maybe open file */
- case 'E': state = sdata(); break; /* Send the data */
- case 'Z': state = seof(); break;
- case 'B': state = sbreak(); break;
- case 'F': state = rfile(); break; /* Receive-File */
- case 'D': state = rdata(); break; /* Receive-Data */
- case 'C': return (TRUE); /* Complete state */
- case 'G': return (FALSE); /* Finish command */
- case 'A':
- default: return (debug ? FALSE : TRUE);
- }
- }
- }
-
- /*
- * f i n i s h s w
- *
- * finishsw is the state table switcher for sending general commands
- * It loops until
- * either it finishes, or an error is encountered. The routines called
- * by finishsw are responsible for changing the state.
- *
- */
-
- finishsw()
- {
- TEXT sfinish();
- n = 0; /* Initialize message number */
- numtry = 0; /* Say no tries yet */
- state = 'F'; /* Send finish is the start state */
- while(TRUE) /* Do this as long as necessary */
- {
- if (debug) printf("Finishsw 1: State: %c\n",state);
- switch(state)
- {
- case 'F': state = sfinish(); break; /* Send-Finish command */
- case 'C': return (TRUE); /* Complete */
- case 'A': /* "Abort" */
- default: return (FALSE); /* Unknown, fail */
- }
- }
- }
-
- /*
- * i i n i t
- *
- * Initiate: send this host's parameters and get other side's back.
- *
- */
-
- TEXT iinit()
- {
- int num, len, slen; /* Packet number, length */
-
- if (numtry++ > 2) return ('R'); /* If too many tries, give up */
- slen = spar(packet0); /* Fill up init info packet */
-
- flushinput(); /* Flush pending input */
-
- eol = MYEOL; /* Preset to my eol character */
- spack('I',n,slen,packet0); /* Send an I packet */
- switch(rpack(&len,&num,recpkt)) /* What was the reply? */
- {
-
- case 'Y': /* ACK */
- if (n != num) /* If wrong ACK, stay in S state */
- { /* Wrong packet number */
- case 'N': /* NAK, Try it again */
- case FALSE:
- nxi++;
- return (state);
- }
- if (!rpar(recpkt,&len)) /* Get the other side's init data */
- return ('A'); /* error with the packet parameters */
-
-
- nxtpkt();
- n = 0; /* Reset packet number to zero */
- return ('R'); /* OK, switch state to R */
-
- case 'E': /* Error packet received */
- prerrpkt(recpkt); /* Print it out and */
- default:
- return ('A'); /* Anything else, just "abort" */
- }
- }
-
- /*
- * s i n i t
- *
- * Send Initiate: send this host's parameters and get other side's back.
- */
-
- TEXT sinit()
- {
- int num, len, slen; /* Packet number, length */
-
- if (numtry++ > MAXTRY) return ('A'); /* If too many tries, give up */
- slen = spar(packet0); /* Fill up init info packet */
-
- flushinput(); /* Flush pending input */
-
- eol = MYEOL; /* Preset to my eol character */
- spack('S',n,slen,packet0); /* Send an S packet */
- switch(rpack(&len,&num,recpkt)) /* What was the reply? */
- {
-
- case 'Y': /* ACK */
- if (n != num) /* If wrong ACK, stay in S state */
- { /* Wrong packet number */
- case 'N': /* NAK, Try it again */
- case FALSE:
- nxi++;
- return (state);
- }
- if (!rpar(recpkt,&len)) /* Get the other side's init data */
- return ('A'); /* error with the packet parameters */
-
-
- nxtpkt();
- return ('T'); /* OK, switch state to T */
-
- case 'E': /* Error packet received */
- prerrpkt(recpkt); /* Print it out and */
- default:
- return ('A'); /* Anything else, just "abort" */
- }
- }
-
- /*
- * r i n i t
- *
- * Receive Initialization
- */
-
- TEXT rinit()
- {
- int len, num, slen; /* Packet length, number */
-
- if (numtry++ > MAXTRY) return ('A'); /* If too many tries, "abort" */
-
- switch(rpack(&len,&num,recpkt)) /* Get a packet */
- {
- case 'S': /* Send-Init packet */
- if (!rpar(recpkt,&len)) /* Get the other side's init data */
- return ('A'); /* error with the packet parameters */
- slen = spar(packet0); /* Fill up packet with my init info */
- spack('Y',n,slen,packet0); /* ACK with my parameters */
- oldtry = numtry; /* Save old try count */
- nxtpkt();
- return ('F'); /* Enter File-Receive state */
-
- case FALSE: /* Didn't get packet */
- nxi++;
- spack('N',n,0,0); /* Return a NAK */
- return (state); /* Keep trying */
-
- case 'E': /* Error packet received */
- prerrpkt(recpkt); /* Print it out and */
- default:
- return ('A'); /* Some other packet type, "abort" */
- }
- }
- /* pe7mai.c End-of-file */
-